﻿namespace System.Linq.Expressions
{
    /// <summary>
    /// Expression扩展方法
    /// </summary>
    public static class ExpressionExtend
    {
        /// <summary>
        /// 合并表达式并返回(and条件)
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="expr1"></param>
        /// <param name="expr2"></param>
        /// <returns></returns>
        public static Expression<Func<TEntity, bool>> And<TEntity>(this Expression<Func<TEntity, bool>> expr1, Expression<Func<TEntity, bool>> expr2)
        {
            ParameterExpression newParameter = Expression.Parameter(typeof(TEntity), "c");
            NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
            var left = visitor.Replace(expr1.Body);
            var right = visitor.Replace(expr2.Body);
            var body = Expression.And(left, right);
            return Expression.Lambda<Func<TEntity, bool>>(body, newParameter);

        }

        /// <summary>
        /// 根据条件合并表达式并返回
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="expr1"></param>
        /// <param name="condition"></param>
        /// <param name="expr2"></param>
        /// <returns></returns>
        public static Expression<Func<TEntity, bool>> And<TEntity>(this Expression<Func<TEntity, bool>> expr1, bool condition, Expression<Func<TEntity, bool>> expr2)
        {
            if (!condition)
            {
                return expr1;
            }
            ParameterExpression newParameter = Expression.Parameter(typeof(TEntity), "c");
            NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
            var left = visitor.Replace(expr1.Body);
            var right = visitor.Replace(expr2.Body);
            var body = Expression.And(left, right);
            return Expression.Lambda<Func<TEntity, bool>>(body, newParameter);

        }

        /// <summary>
        /// 合并表达式并返回(or条件)
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="expr1"></param>
        /// <param name="expr2"></param>
        /// <returns></returns>
        public static Expression<Func<TEntity, bool>> Or<TEntity>(this Expression<Func<TEntity, bool>> expr1, Expression<Func<TEntity, bool>> expr2)
        {

            ParameterExpression newParameter = Expression.Parameter(typeof(TEntity), "c");
            NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);

            var left = visitor.Replace(expr1.Body);
            var right = visitor.Replace(expr2.Body);
            var body = Expression.Or(left, right);
            return Expression.Lambda<Func<TEntity, bool>>(body, newParameter);
        }
        public static Expression<Func<TEntity, bool>> Not<TEntity>(this Expression<Func<TEntity, bool>> expr)
        {
            var candidateExpr = expr.Parameters[0];
            var body = Expression.Not(expr.Body);

            return Expression.Lambda<Func<TEntity, bool>>(body, candidateExpr);
        }
    }

    /// <summary>
    /// 建立新表达式
    /// </summary>
    internal class NewExpressionVisitor : ExpressionVisitor
    {
        public ParameterExpression _NewParameter { get; private set; }
        public NewExpressionVisitor(ParameterExpression param)
        {
            this._NewParameter = param;
        }
        public Expression Replace(Expression exp)
        {
            return this.Visit(exp);
        }
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return this._NewParameter;
        }
    }
}
